﻿using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Mvc.Ajax;
using System.Text;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Web.UI.WebControls;
using System.Web.Routing;

namespace CoolCode.Web.Mvc
{
    /// <summary>
    /// This helper method renders a link within an HTML LI tag.
    /// A class="selected" attribute is added to the tag when
    /// the link being rendered corresponds to the current
    /// controller and action.
    /// 
    /// This helper method is used in the Site.Master View 
    /// Master Page to display the website menu.
    /// </summary>
    public static class MenuItemHelper
    {
        public static string MenuItem(this HtmlHelper helper, string linkText, string actionName, string controllerName)
        {
            return MenuItem(helper, linkText, actionName, controllerName, null, null);
        }

        public static string MenuItem(this HtmlHelper helper, string linkText, string actionName, object routeValues)
        {
            return MenuItem(helper, linkText, actionName, null, routeValues, null);
        }

        public static string MenuItem(this HtmlHelper helper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
        {
            string currentControllerName = (string)helper.ViewContext.RouteData.Values["controller"];
            string currentActionName = (string)helper.ViewContext.RouteData.Values["action"];

            var builder = new TagBuilder("li");

            // Add selected class
            if (currentControllerName.Equals(controllerName, StringComparison.CurrentCultureIgnoreCase) && currentActionName.Equals(actionName, StringComparison.CurrentCultureIgnoreCase))
                builder.AddCssClass("selected");

            // Add link
            MvcHtmlString mvcHtml = helper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);
            builder.InnerHtml = mvcHtml.ToHtmlString();

            // Render Tag Builder
            return builder.ToString(TagRenderMode.Normal);
        }
    }

    public static class SelectedHelper
    {
        public static string Selected<T>(this HtmlHelper helper, T value1, T value2)
        {
            if (value1.Equals(value2))
                return "class=\"selected\"";
            return String.Empty;
        }
    }


    public static class ImageActionLinkHelper
    {
        public static string ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, object routeValues, AjaxOptions ajaxOptions)
        {
            var builder = new TagBuilder("img");
            builder.MergeAttribute("src", imageUrl);
            builder.MergeAttribute("alt", altText);
            var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions);
            var html = link.ToHtmlString();
            return html.Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing));
        }
    }


    public static class PagerHelper
    {
        /// <summary>  
        /// 分页Pager显示  
        /// </summary>   
        /// <param name="html"></param>  
        /// <param name="currentPageStr">标识当前页码的QueryStringKey</param>   
        /// <param name="pageSize">每页显示</param>  
        /// <param name="totalCount">总数据量</param>  
        /// <returns></returns> 
        public static string Pager(this HtmlHelper html, string currentPageStr, int pageSize, int totalCount)
        {
            var queryString = html.ViewContext.HttpContext.Request.QueryString;
            int currentPage = 1; //当前页  
            var totalPages = Math.Max((totalCount + pageSize - 1) / pageSize, 1); //总页数  
            var dict = new System.Web.Routing.RouteValueDictionary(html.ViewContext.RouteData.Values);
            var output = new StringBuilder();
            if (!string.IsNullOrEmpty(queryString[currentPageStr]))
            {
                //与相应的QueryString绑定 
                foreach (string key in queryString.Keys)
                    if (queryString[key] != null && !string.IsNullOrEmpty(key))
                        dict[key] = queryString[key];
                int.TryParse(queryString[currentPageStr], out currentPage);
            }
            else
            {
                //获取 ～/Page/{page number} 的页号参数
                if (dict.ContainsKey(currentPageStr))
                    int.TryParse(dict[currentPageStr].ToString(), out currentPage);
            }

            //保留查询字符到下一页
            foreach (string key in queryString.Keys)
                dict[key] = queryString[key];

            //如果有需要，保留表单值到下一页 (我暂时不需要， 所以注释掉)
            //var formValue = html.ViewContext.HttpContext.Request.Form;
            //foreach (string key in formValue.Keys)
            //    if (formValue[key] != null && !string.IsNullOrEmpty(key))
            //        dict[key] = formValue[key]; 

            if (currentPage <= 0) currentPage = 1;
            if (totalPages > 1)
            {
                if (currentPage != 1)
                {
                    //处理首页连接  
                    dict[currentPageStr] = 1;
                    output.AppendFormat("{0} ", html.RouteLink("首页", dict));
                }
                if (currentPage > 1)
                {
                    //处理上一页的连接  
                    dict[currentPageStr] = currentPage - 1;
                    output.Append(html.RouteLink("上一页", dict));
                }
                else
                {
                    output.Append("上一页");
                }
                output.Append(" ");
                int currint = 5;
                for (int i = 0; i <= 10; i++)
                {
                    //一共最多显示10个页码，前面5个，后面5个  
                    if ((currentPage + i - currint) >= 1 && (currentPage + i - currint) <= totalPages)
                        if (currint == i)
                        {
                            //当前页处理  
                            output.Append(string.Format("[{0}]", currentPage));
                        }
                        else
                        {
                            //一般页处理 
                            dict[currentPageStr] = currentPage + i - currint;
                            output.Append(html.RouteLink((currentPage + i - currint).ToString(), dict));
                        }
                    output.Append(" ");
                }
                if (currentPage < totalPages)
                {
                    //处理下一页的链接 
                    dict[currentPageStr] = currentPage + 1;
                    output.Append(html.RouteLink("下一页", dict));
                }
                else
                {
                    output.Append("下一页");
                }
                output.Append(" ");
                if (currentPage != totalPages)
                {
                    dict[currentPageStr] = totalPages;
                    output.Append(html.RouteLink("末页", dict));
                }
                output.Append(" ");
            }
            output.AppendFormat("{0} / {1}", currentPage, totalPages);//这个统计加不加都行 
            return output.ToString();
        }
    }

    public static class TableHelper
    {
        /// <summary>
        /// Sample：<%=Html.Table("myTable", (IList)ViewData.Model, null) %>
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="name"></param>
        /// <param name="items"></param>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public static string Table(this HtmlHelper helper, string name, IList items, IDictionary<string, object> attributes)
        {
            if (items == null || items.Count == 0 || string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }

            return BuildTable(name, items, attributes);
        }

        private static string BuildTable(string name, IList items, IDictionary<string, object> attributes)
        {
            StringBuilder sb = new StringBuilder();
            BuildTableHeader(sb, items[0].GetType());

            foreach (var item in items)
            {
                BuildTableRow(sb, item);
            }

            TagBuilder builder = new TagBuilder("table");
            builder.MergeAttributes(attributes);
            builder.MergeAttribute("name", name);
            builder.InnerHtml = sb.ToString();
            return builder.ToString(TagRenderMode.Normal);
        }

        private static void BuildTableRow(StringBuilder sb, object obj)
        {
            Type objType = obj.GetType();
            sb.AppendLine("\t<tr>");
            foreach (var property in objType.GetProperties())
            {
                sb.AppendFormat("\t\t<td>{0}</td>\n", property.GetValue(obj, null));
            }
            sb.AppendLine("\t</tr>");
        }

        private static void BuildTableHeader(StringBuilder sb, Type p)
        {
            sb.AppendLine("\t<tr>");
            foreach (var property in p.GetProperties())
            {
                sb.AppendFormat("\t\t<th>{0}</th>\n", property.Name);
            }
            sb.AppendLine("\t</tr>");
        }
    }


    /// <summary>
    /// Extension methods on IEnumerable.
    /// </summary>
    public static class EnumerableExtensions
    {
        static public List<ListItem> ToListItem<T>()
        {
            var li = new List<ListItem>();
            foreach (int s in Enum.GetValues(typeof(T)))
            {
                li.Add(new ListItem
                {
                    Value = s.ToString(),
                    Text = Enum.GetName(typeof(T), s)
                }
                );
            }
            return li;
        }
        /// <summary>
        /// Converts an enumerable into a SelectList.
        /// </summary>
        /// <typeparam name="T">Type of item in the collection</typeparam>
        /// <typeparam name="TValueField">Type of the value field</typeparam>
        /// <param name="items">Items to convert into a select list</param>
        /// <param name="valueFieldSelector">Expression used to identify the data value field</param>
        /// <param name="textFieldSelector">Expression used to identify the data text field</param>
        /// <returns>A populated SelectList</returns>
        public static SelectList ToSelectList<T, TValueField>(this IEnumerable<T> items, Expression<Func<T, TValueField>> valueFieldSelector, Expression<Func<T, object>> textFieldSelector)
        {
            string textField = ExpressionToName(textFieldSelector);
            string valueField = ExpressionToName(valueFieldSelector);

            return new SelectList(items, valueField, textField);
        }

        /// <summary>
        /// Converts an enumerable into a SelectList.
        /// </summary>
        /// <typeparam name="T">Type of item in the collection</typeparam>
        /// <typeparam name="TValueField">Type of the value field</typeparam>
        /// <param name="items">Items to convert into a select list</param>
        /// <param name="valueFieldSelector">Expression used to identify the data value field</param>
        /// <param name="textFieldSelector">Expression used to identify the data text field</param>
        /// <param name="selectedValue">The selected value</param>
        /// <returns>A populated SelectList</returns>
        public static SelectList ToSelectList<T, TValueField>(this IEnumerable<T> items, Expression<Func<T, TValueField>> valueFieldSelector, Expression<Func<T, object>> textFieldSelector, TValueField selectedValue)
        {
            string textField = ExpressionToName(textFieldSelector);
            string valueField = ExpressionToName(valueFieldSelector);

            return new SelectList(items, valueField, textField, selectedValue);
        }

        /// <summary>
        /// Converts an enumerable into a SelectList.
        /// </summary>
        /// <typeparam name="T">Type of item in the collection</typeparam>
        /// <typeparam name="TValueField">Type of the value field</typeparam>
        /// <param name="items">Items to convert into a select list</param>
        /// <param name="valueFieldSelector">Expression used to identify the data value field</param>
        /// <param name="textFieldSelector">Expression used to identify the data text field</param>
        /// <param name="selectedValueSelector">A predicate that can be used to specify which values should be selected</param>
        /// <returns>A populated SelectList</returns>
        public static MultiSelectList ToSelectList<T, TValueField>(this IEnumerable<T> items, Expression<Func<T, TValueField>> valueFieldSelector, Expression<Func<T, object>> textFieldSelector, Func<T, bool> selectedValueSelector)
        {
            var selectedItems = items.Where(selectedValueSelector);
            string textField = ExpressionToName(textFieldSelector);
            string valueField = ExpressionToName(valueFieldSelector);

            return new MultiSelectList(items, valueField, textField, selectedItems);
        }

        private static string ExpressionToName<T, TValue>(Expression<Func<T, TValue>> expression)
        {
            var memberExpression = RemoveUnary(expression.Body) as MemberExpression;
            return memberExpression == null ? string.Empty : memberExpression.Member.Name;
        }

        private static Expression RemoveUnary(Expression body)
        {
            var unary = body as UnaryExpression;
            if (unary != null)
            {
                return unary.Operand;
            }
            return body;
        }
    }

    public static class CheckBoxExtensions
    {
        //public static MvcHtmlString CheckBoxList(this HtmlHelper helper, string name, params string[] items)
        //{
        //    StringBuilder sb = new StringBuilder();
        //    int i = 0;
        //    foreach (string item in items)
        //    {
        //        string checkbox = helper.CheckBox(name + "." + i).ToHtmlString();
        //        string label = helper.Encode(item + " ");
        //        sb.Append(checkbox);
        //        sb.Append(label);
        //        i++;
        //    }
        //    return MvcHtmlString.Create(sb.ToString());
        //}


        public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<SelectListItem> listInfo)
        {
            return htmlHelper.CheckBoxList(name, listInfo, ((IDictionary<string, object>)null));
        }

        public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<SelectListItem> listInfo, object htmlAttributes)
        {
            return htmlHelper.CheckBoxList(name, listInfo, ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
        }

        public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<SelectListItem> listInfo, IDictionary<string, object> htmlAttributes)
        {
            if (String.IsNullOrEmpty(name))
                throw new ArgumentException("The argument must have a value", "name");
            if (listInfo == null)
                throw new ArgumentNullException("listInfo");
            //if (listInfo.Count ()< 1)
            //    throw new ArgumentException("The list must contain at least one value", "listInfo");

            StringBuilder sb = new StringBuilder();
            foreach (SelectListItem info in listInfo)
            {
                TagBuilder builder = new TagBuilder("input");
                if (info.Selected ) builder.MergeAttribute("checked", "checked");
                builder.MergeAttributes<string, object>(htmlAttributes);
                builder.MergeAttribute("type", "checkbox");
                builder.MergeAttribute("value", info.Value );//== bool.FalseString ?"unchecked"
                builder.MergeAttribute("name", name);
                //builder.InnerHtml = info.Text;
                //sb.Append(builder.ToString(TagRenderMode.Normal));
                builder.GenerateId(info.Value);
                TagBuilder labelBuilder = new TagBuilder("label");
                labelBuilder.MergeAttribute("for", builder.Attributes["id"]);
                labelBuilder.InnerHtml = info.Text;
                sb.Append(builder.ToString(TagRenderMode.SelfClosing));
                sb.Append(labelBuilder.ToString(TagRenderMode.Normal));
               // sb.Append("<br />");
            }

            return sb.ToString();
        }
    }

    //// This the information that is needed by each checkbox in the
    //// CheckBoxList helper.
    //public class CheckBoxListInfo
    //{
    //    public CheckBoxListInfo(string value, string displayText, bool isChecked)
    //    {
    //        this.Value = value; 
    //        this.DisplayText = displayText;
    //        this.IsChecked = isChecked;
    //    }

    //    public string Value { get; private set; }
    //    public string DisplayText { get; private set; }
    //    public bool IsChecked { get; private set; }
    //}

    //public class CheckBoxList : MvcHtmlString
    //{
    //    HtmlHelper _helper;
    //    string[] _items;
    //    public CheckBoxList(HtmlHelper helper, params string[] items)
    //    {
    //        _helper = helper;
    //        _items = items;
    //    }

    //    public override string ToString()
    //    {
    //         return base.ToString();
    //    }
    //}

}
